﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace PO_2011
{
    public partial class HistogramForm : Form
    {
        private const int histoWidth = 256;
        private const int histoHeight = 100;
        private const int colorCount = 256;

        private PictureBox imageBox;
        private Bitmap histoBitmapL;
        private Bitmap histoBitmapR;
        private Bitmap histoBitmapG;
        private Bitmap histoBitmapB;

        int[] cumulChannelR;
        int[] cumulChannelG;
        int[] cumulChannelB;

        public HistogramForm(PictureBox sourceImageBox)
        {
            InitializeComponent();

            imageBox = sourceImageBox;
            DrawHistogram();
        }

        public void DrawHistogram()
        {
            Bitmap image = new Bitmap(imageBox.Image);

            int[] channelL = new int[colorCount];
            int[] channelR = new int[colorCount];
            int[] channelG = new int[colorCount];
            int[] channelB = new int[colorCount];
            Histogram.CalcHistogram(image, colorCount, out channelL, out channelR, out channelG, out channelB);
            
            /*for (int y = 0; y < image.Height; y++)
            {
                for (int x = 0; x < image.Width; x++)
                {
                    Color c = image.GetPixel(x, y);
                    channelL[(int)Math.Ceiling((c.R * 0.587) + (c.G * 0.299) + (c.B * 0.114))]++;
                    channelR[c.R]++;
                    channelG[c.G]++;
                    channelB[c.B]++;
                }
            }*/

            cumulChannelR = (int[])channelR.Clone();
            cumulChannelG = (int[])channelG.Clone();
            cumulChannelB = (int[])channelB.Clone();

            for (int i = 1; i < colorCount; i++)
            {
                cumulChannelR[i] += cumulChannelR[i - 1];
                cumulChannelG[i] += cumulChannelG[i - 1];
                cumulChannelB[i] += cumulChannelB[i - 1];
            }

            float scaleL = 0;
            float scaleR = 0;
            float scaleG = 0;
            float scaleB = 0;

            for (int i = 0; i < colorCount; i++)
            {
                if (scaleL < channelL[i]) scaleL = channelL[i];
                if (scaleR < channelR[i]) scaleR = channelR[i];
                if (scaleG < channelG[i]) scaleG = channelG[i];
                if (scaleB < channelB[i]) scaleB = channelB[i];
            }

            scaleL = histoHeight / scaleL;
            scaleR = histoHeight / scaleR;
            scaleG = histoHeight / scaleG;
            scaleB = histoHeight / scaleB;

            for (int i = 0; i < colorCount; i++)
            {
                channelL[i] = (int)(channelL[i] * scaleL);
                channelR[i] = (int)(channelR[i] * scaleR);
                channelG[i] = (int)(channelG[i] * scaleG);
                channelB[i] = (int)(channelB[i] * scaleB);
            }

            histoBitmapL = new Bitmap(histoWidth, histoHeight);
            histoBitmapR = new Bitmap(histoWidth, histoHeight);
            histoBitmapG = new Bitmap(histoWidth, histoHeight);
            histoBitmapB = new Bitmap(histoWidth, histoHeight);
 
            for (int x = 0; x < colorCount; x++)
            {
                for (int y = 0; y < channelL[x]; y++)
                {
                    histoBitmapL.SetPixel(x, histoHeight - 1 - y, Color.Black);
                }
                for (int y = 0; y < channelR[x]; y++)
                {
                    histoBitmapR.SetPixel(x, histoHeight - 1 - y, Color.Black);
                }
                for (int y = 0; y < channelG[x]; y++)
                {
                    histoBitmapG.SetPixel(x, histoHeight - 1 - y, Color.Black);
                }
                for (int y = 0; y < channelB[x]; y++)
                {
                    histoBitmapB.SetPixel(x, histoHeight - 1 - y, Color.Black);
                }
            }

            if (histoLRadio.Checked) SwitchChannel('L');
            else if (histoRRadio.Checked) SwitchChannel('R');
            else if (histoGRadio.Checked) SwitchChannel('G');
            else if (histoBRadio.Checked) SwitchChannel('B');
        }

        public void SwitchChannel(char channel)
        {
            switch (channel)
            {
                case 'L':
                    histoPictureBox.Image = histoBitmapL;
                    break;
                case 'R':
                    histoPictureBox.Image = histoBitmapR;
                    break;
                case 'G':
                    histoPictureBox.Image = histoBitmapG;
                    break;
                case 'B':
                    histoPictureBox.Image = histoBitmapB;
                    break;
            }
        }

        private void histoRadio_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton box = (RadioButton)sender;
            if (box.Checked)
            {
                SwitchChannel(box.Text[0]);
            }
        }

        private void histoEqualizeButton_Click(object sender, EventArgs e)
        {
            Bitmap img = new Bitmap(imageBox.Image);
            Bitmap eqImg = new Bitmap(img.Width, img.Height);

            int pCount = img.Height * img.Width;

            int[] eqChannelR = new int[colorCount];
            int[] eqChannelG = new int[colorCount];
            int[] eqChannelB = new int[colorCount];

            for (int i = 0; i < colorCount; i++)
            {
                eqChannelR[i] = (colorCount - 1) * (cumulChannelR[i] - cumulChannelR[0]) / (pCount - cumulChannelR[0]);
                eqChannelG[i] = (colorCount - 1) * (cumulChannelG[i] - cumulChannelG[0]) / (pCount - cumulChannelG[0]);
                eqChannelB[i] = (colorCount - 1) * (cumulChannelB[i] - cumulChannelB[0]) / (pCount - cumulChannelB[0]);
            }

            for (int y = 0; y < img.Height; y++)
            {
                for (int x = 0; x < img.Width; x++)
                {
                    Color c = img.GetPixel(x, y);
                    eqImg.SetPixel(x, y, Color.FromArgb(eqChannelR[c.R], eqChannelG[c.G], eqChannelB[c.B]));
                }
            }

            imageBox.Image = eqImg;
            DrawHistogram();
        }

        private void histoStretchButton_Click(object sender, EventArgs e)
        {
            Bitmap img = new Bitmap(imageBox.Image);
            Bitmap eqImg = new Bitmap(img.Width, img.Height);

            int pCount = img.Height * img.Width;

            int[] stretchChannelR = new int[colorCount];
            int[] stretchChannelG = new int[colorCount];
            int[] stretchChannelB = new int[colorCount];

            for (int i = 0; i < colorCount; i++)
            {
                stretchChannelR[i] = (int)(i * cumulChannelR[i] / pCount);
                stretchChannelG[i] = (int)(i * cumulChannelG[i] / pCount);
                stretchChannelB[i] = (int)(i * cumulChannelB[i] / pCount);
            }

            for (int y = 0; y < img.Height; y++)
            {
                for (int x = 0; x < img.Width; x++)
                {
                    Color c = img.GetPixel(x, y);
                    eqImg.SetPixel(x, y, Color.FromArgb(stretchChannelR[c.R], stretchChannelG[c.G], stretchChannelB[c.B]));
                }
            }

            imageBox.Image = eqImg;
            DrawHistogram();
        }
    }
}
